/*
 * Copyright 2011 Dominik Pretzsch <dominik.pretzsch at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.blacksheep.jmoteextract.archive;

import de.blacksheep.jmoteextract.archive.callback.ArchiveExtractCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.sevenzipjbinding.ISevenZipInArchive;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;

/**
 * <code>ArchiveExtractor</code> provides the actual extraction interface. <br> 
 * The extraction process is prepared and started here.
 * 
 * @author Dominik Pretzsch <dominik.pretzsch at gmail.com>
 */
class ArchiveExtractor {
    
    private Archive archive;
    
    private static final boolean TEST_MODE = false;  
    private static final Logger  LOGGER    = Logger.getLogger(ArchiveExtractor.class.getName());
    
    public ArchiveExtractor(Archive archive) throws SevenZipNativeInitializationException {
        SevenZip.initSevenZipFromPlatformJAR();
        LOGGER.log(Level.FINE, "7-Zip-JBinding successfully initialized");
        
        this.archive = archive;
    }
    
    /**
     * Starts the extraction process.
     * 
     * @throws SevenZipException 
     * @TODO: prepare extraction, ...
     */
    public void extract() 
                throws SevenZipException {
                                        
        LOGGER.log(Level.FINE, "Try to extract {0}", archive.getFileName());
        
        ISevenZipInArchive inArchive  = archive.getInArchive();
        String absoluteExtractionPath = archive.getAbsoluteExtractionPath();
        
        if (inArchive == null) {
            throw new SevenZipException("Archive has not been opened!");
        }
        
        int count = inArchive.getNumberOfItems();
        List<Integer> itemsToExtract = new ArrayList<Integer>();
        
        LOGGER.log(Level.FINE, "Number of items interface archive: {0}", count);
        
        File extractionDir = new File(absoluteExtractionPath);
        //if (!extractionDir.exists() || !extractionDir.isDirectory()){
        if (!extractionDir.exists()){
            LOGGER.log(Level.FINE, "{0} does not exist. Try to mkdirs", absoluteExtractionPath);
            extractionDir.mkdirs();
        }
        
        for (int i = 0; i < count; i++) {
            if (!((Boolean) inArchive.getProperty(i, PropID.IS_FOLDER)).booleanValue()) {
                LOGGER.log(Level.FINE, "Detected Item: {0}", inArchive.getProperty(i, PropID.PATH));
                itemsToExtract.add(Integer.valueOf(i));
            } else {
                LOGGER.log(Level.FINE, "Detected Directory: {0}", inArchive.getProperty(i, PropID.PATH));
                String filePath = (String) inArchive.getProperty(i, PropID.PATH);
                String extPath = absoluteExtractionPath.concat("\\").concat(filePath);
                
                File dir = new File(extPath);
                if (!dir.exists()) {
                    LOGGER.log(Level.FINE, "Directory {0} created", inArchive.getProperty(i, PropID.PATH));
                    dir.mkdirs();
                }
            }
        }
        
        LOGGER.log(Level.FINE, "Items to extract: {0}", itemsToExtract.size());
        
        int[] items = new int[itemsToExtract.size()];
        int i = 0;
        
        for (Integer integer : itemsToExtract) {
            items[i++] = integer.intValue();
        }
        
        ArchiveExtractCallback aec = new ArchiveExtractCallback(archive);
        aec.setNumberOfItems(items.length);
        
        LOGGER.log(Level.FINE, "Starting extraction");
        inArchive.extract(items, TEST_MODE, aec);
        LOGGER.log(Level.FINE, "Extraction finished");
    }
}
